---
title: Messages
---

{/* TODO: section on metadata types (response and usage) */}

import AlphaCallout from '/snippets/alpha-lc-callout.mdx';

<AlphaCallout />

Messages are the fundamental unit of context for models in LangChain. They represent the input and output of models, carrying both the content and metadata needed to represent the state of a conversation when interacting with an LLM.

Messages are objects that contain:

* <Icon icon="user" size={16} /> [**Role**](#message-types) - Identifies the message type (e.g. `system`, `user`)
* <Icon icon="folder-closed" size={16} /> [**Content**](#content) - Represents the actual content of the message (like text, images, audio, documents, etc.)
* <Icon icon="tag" size={16} /> [**Metadata**](#message-metadata) - Optional fields such as response information, message IDs, and token usage

LangChain provides a standard message type that works across all model providers, ensuring consistent behavior regardless of the model being called.

## Basic usage

The simplest way to use messages is to create message objects and pass them to a model when [invoking](/oss/langchain/models#invocation).

:::python
```python
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage

model = init_chat_model("openai:gpt-5-nano")

system_msg = SystemMessage("You are a helpful assistant.")
human_msg = HumanMessage("Hello, how are you?")

# Use with chat models
messages = [system_msg, human_msg]
response = model.invoke(messages)  # Returns AIMessage
```
:::

:::js
```typescript
import { initChatModel, HumanMessage, SystemMessage } from "langchain";

const model = await initChatModel("openai:gpt-5-nano");

const systemMsg = new SystemMessage("You are a helpful assistant.");
const humanMsg = new HumanMessage("Hello, how are you?");

const messages = [systemMsg, humanMsg];
const response = await model.invoke(messages);  // Returns AIMessage
```
:::

### Text prompts

Text prompts are strings - ideal for straightforward generation tasks where you don't need to retain conversation history.

:::python
```python
response = model.invoke("Write a haiku about spring")
```
:::

:::js
```typescript
const response = await model.invoke("Write a haiku about spring");
```
:::

**Use text prompts when:**
* You have a single, standalone request
* You don't need conversation history
* You want minimal code complexity

### Message prompts

Alternatively, you can pass in a list of messages to the model by providing a list of message objects.

:::python
```python
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage

messages = [
    SystemMessage("You are a poetry expert"),
    HumanMessage("Write a haiku about spring"),
    AIMessage("Cherry blossoms bloom...")
]
response = model.invoke(messages)
```
:::

:::js
```typescript
import { SystemMessage, HumanMessage, AIMessage } from "langchain";

const messages = [
    new SystemMessage("You are a poetry expert"),
    new HumanMessage("Write a haiku about spring"),
    new AIMessage("Cherry blossoms bloom...")
]
const response = await model.invoke(messages);
```
:::

**Use message prompts when:**
* Managing multi-turn conversations
* Working with multimodal content (images, audio, files)
* Including system instructions

### Dictionary format

You can also specify messages directly in OpenAI chat completions format.

:::python
```python
messages = [
    {"role": "system", "content": "You are a poetry expert"},
    {"role": "user", "content": "Write a haiku about spring"},
    {"role": "assistant", "content": "Cherry blossoms bloom..."}
]
response = model.invoke(messages)
```
:::

:::js
```typescript
const messages = [
    { role: "system", content: "You are a poetry expert" },
    { role: "user", content: "Write a haiku about spring" },
    { role: "assistant", content: "Cherry blossoms bloom..." }
]
const response = await model.invoke(messages);
```
:::

## Message types

- <Icon icon="gear" size={16} /> [System message](#system-message) - Tells the model how to behave and provide context for interactions
- <Icon icon="user" size={16} /> [Human message](#human-message) - Represents user input and interactions with the model
- <Icon icon="robot" size={16} /> [AI message](#ai-message) - Responses generated by the model, including text content, tool calls, and metadata
- <Icon icon="wrench" size={16} /> [Tool message](#tool-message) - Represents the outputs of tool calls

### System Message

A `SystemMessage` represent an initial set of instructions that primes the model's behavior. You can use a system message to set the tone, define the model's role, and establish guidelines for responses.

:::python
```python Basic instructions
system_msg = SystemMessage("You are a helpful coding assistant.")

messages = [
    system_msg,
    HumanMessage("How do I create a REST API?")
]
response = model.invoke(messages)
```
:::

:::js
```typescript Basic instructions
import { SystemMessage, HumanMessage, AIMessage } from "langchain";

const systemMsg = new SystemMessage("You are a helpful coding assistant.");

const messages = [
    systemMsg,
    new HumanMessage("How do I create a REST API?")
]
const response = await model.invoke(messages);
```
:::

:::python
```python Detailed persona
from langchain_core.messages import SystemMessage, HumanMessage

system_msg = SystemMessage("""
You are a senior Python developer with expertise in web frameworks.
Always provide code examples and explain your reasoning.
Be concise but thorough in your explanations.
""")

messages = [
    system_msg,
    HumanMessage("How do I create a REST API?")
]
response = model.invoke(messages)
```
:::

:::js
```typescript Detailed persona
import { SystemMessage, HumanMessage } from "langchain";

const systemMsg = new SystemMessage(`
You are a senior TypeScript developer with expertise in web frameworks.
Always provide code examples and explain your reasoning.
Be concise but thorough in your explanations.
`);

const messages = [
    systemMsg,
    new HumanMessage("How do I create a REST API?")
]
const response = await model.invoke(messages);
```
:::

---

### Human Message

A `HumanMessage` represents user input and interactions. They can contain text, images, audio, files, and any other amount of multimodal [content](#content).

#### Text content

:::python
<CodeGroup>
    ```python Message object
    human_msg = HumanMessage("What is machine learning?")
    response = model.invoke([human_msg])
    ```

    ```python String shortcut
    # Using a string is a shortcut for a single HumanMessage
    response = model.invoke("What is machine learning?")
    ```
</CodeGroup>
:::

:::js
```typescript Message object
const humanMsg = new HumanMessage("What is machine learning?");
const response = await model.invoke([humanMsg]);
```

```typescript String shortcut
const response = await model.invoke("What is machine learning?");
```
:::

#### Message metadata

:::python
```python Add metadata
human_msg = HumanMessage(
    content="Hello!",
    name="alice",  # Optional: identify different users
    id="msg_123",  # Optional: unique identifier for tracing
)
```
:::

:::js
```typescript Add metadata
const humanMsg = new HumanMessage({
    content: "Hello!",
    name: "alice",
    id: "msg_123"
});
```
:::

<Note>
    The `name` field behavior varies by provider - some use it for user identification, others ignore it. To check, refer to the model provider's @[reference][Reference].
</Note>

---

### AI Message

An `AIMessage` represents the output of a model invocation. They can include multimodal data, tool calls, and provider-specific metadata that you can later access.

:::python
```python
response = model.invoke("Explain AI")
print(type(response))  # <class 'langchain_core.messages.AIMessage'>
```
:::

:::js
```typescript
const response = await model.invoke("Explain AI");
console.log(typeof response);  // AIMessage
```
:::

`AIMessage` objects are returned by the model when calling it, which contains all of the associated metadata in the response. However, that doesn't mean that's the only place they can be created/ modified from.

Providers weight/contextualize types of messages differently, which means it is sometimes helpful to create a new `AIMessage` object and insert it into the message history as if it came from the model.

:::python
```python
from langchain_core.messages import AIMessage, SystemMessage, HumanMessage

# Create an AI message manually (e.g., for conversation history)
ai_msg = AIMessage("I'd be happy to help you with that question!")

# Add to conversation history
messages = [
    SystemMessage("You are a helpful assistant"),
    HumanMessage("Can you help me?"),
    ai_msg,  # Insert as if it came from the model
    HumanMessage("Great! What's 2+2?")
]

response = model.invoke(messages)
```
:::

:::js
```typescript
import { AIMessage, SystemMessage, HumanMessage } from "langchain";

const aiMsg = new AIMessage("I'd be happy to help you with that question!");

const messages = [
    new SystemMessage("You are a helpful assistant"),
    new HumanMessage("Can you help me?"),
    aiMsg,  // Insert as if it came from the model
    new HumanMessage("Great! What's 2+2?")
]

const response = await model.invoke(messages);
```
:::

<Accordion title="Attributes">
    :::python
    <ParamField path="text" type="string">
        The text content of the message.
    </ParamField>
    <ParamField path="content" type="string | dict[]">
        The raw content of the message.
    </ParamField>
    <ParamField path="content_blocks" type="ContentBlock[]">
        The standardized [content blocks](#content) of the message.
    </ParamField>
    <ParamField path="tool_calls" type="dict[] | None">
        The tool calls made by the model. Empty if no tools are called.
    </ParamField>
    <ParamField path="id" type="string">
        A unique identifier for the message (either automatically generated by LangChain or returned in the provider response)
    </ParamField>
    <ParamField path="usage_metadata" type="dict | None">
        The usage metadata of the message, which can contain token counts when available.
    </ParamField>
    <ParamField path="response_metadata" type="ResponseMetadata | None">
        The response metadata of the message.
    </ParamField>
    :::

    :::js
    <ParamField path="text" type="string">
        The text content of the message.
    </ParamField>
    <ParamField path="content" type="string | ContentBlock[]">
        The raw content of the message.
    </ParamField>
    <ParamField path="content_blocks" type="ContentBlock.Standard[]">
        The standardized content blocks of the message. (See [content](#content))
    </ParamField>
    <ParamField path="tool_calls" type="ToolCall[] | None">
        The tool calls made by the model. Empty if no tools are called.
    </ParamField>
    <ParamField path="id" type="string">
        A unique identifier for the message (either automatically generated by LangChain or returned in the provider response)
    </ParamField>
    <ParamField path="usage_metadata" type="UsageMetadata | None">
        The usage metadata of the message, which can contain token counts when available.
    </ParamField>
    <ParamField path="response_metadata" type="ResponseMetadata | None">
        The response metadata of the message.
    </ParamField>
    :::
</Accordion>

#### Tool calling responses

When models make tool calls, they're included in the AI message:

:::python
```python Tool calling
model_with_tools = model.bind_tools([GetWeather])
response = model_with_tools.invoke("What's the weather in Paris?")

for tool_call in response.tool_calls:
    print(f"Tool: {tool_call['name']}")
    print(f"Args: {tool_call['args']}")
    print(f"ID: {tool_call['id']}")
```
:::

:::js
```typescript
const modelWithTools = model.bindTools([getWeather]);
const response = await modelWithTools.invoke("What's the weather in Paris?");

for (const toolCall of response.tool_calls) {
    console.log(`Tool: ${toolCall.name}`);
    console.log(`Args: ${toolCall.args}`);
    console.log(`ID: ${toolCall.id}`);
}
```
:::

#### Streaming and chunks

During streaming, you'll receive `AIMessageChunk` objects that can be combined into a full message:

:::python
```python
chunks = []
full_message = None
for chunk in model.stream("Hi"):
    chunks.append(chunk)
    print(chunk.text)
    full_message = chunk if full_message is None else full_message + chunk
```
:::

:::js
<CodeGroup>
```typescript
import { AIMessageChunk } from "langchain";

let finalChunk: AIMessageChunk | undefined;
for (const chunk of chunks) {
    finalChunk = finalChunk ? finalChunk.concat(chunk) : chunk;
}
```
</CodeGroup>
:::

---

### Tool Message

For models that support tool calling, AI messages can contain tool calls. Tool messages are used to pass the results of a single tool execution back to the model.

:::python
```python
# After a model makes a tool call
ai_message = AIMessage(
    content=[],
    tool_calls=[{
        "name": "get_weather",
        "args": {"location": "San Francisco"},
        "id": "call_123"
    }]
)

# Execute tool and create result message
weather_result = "Sunny, 72°F"
tool_message = ToolMessage(
    content=weather_result,
    tool_call_id="call_123"  # Must match the call ID
)

# Continue conversation
messages = [
    HumanMessage("What's the weather in San Francisco?"),
    ai_message,  # Model's tool call
    tool_message,  # Tool execution result
]
response = model.invoke(messages)  # Model processes the result
```
:::

:::js
```typescript
import { AIMessage, ToolMessage } from "langchain";

const aiMessage = new AIMessage({
    content: [],
    tool_calls: [{
        name: "get_weather",
        args: { location: "San Francisco" },
        id: "call_123"
    }]
});

const toolMessage = new ToolMessage({
    content: "Sunny, 72°F",
    tool_call_id: "call_123"
});

const messages = [
    new HumanMessage("What's the weather in San Francisco?"),
    aiMessage,  // Model's tool call
    toolMessage,  // Tool execution result
];

const response = await model.invoke(messages);  // Model processes the result
```
:::

<Accordion title="Attributes">
    <ParamField path="content" type="string" required>
        The stringified output of the tool call.
    </ParamField>
    <ParamField path="tool_call_id" type="string" required>
        The ID of the tool call that this message is responding to. (this must match the ID of the tool call in the AI message)
    </ParamField>
    <ParamField path="name" type="string" required>
        The name of the tool that was called.
    </ParamField>
    <ParamField path="artifact" type="dict">
        Additional data not sent to the model but can be accessed programmatically.
    </ParamField>

    <Note>
        The `artifact` field stores supplementary data that won't be sent to the model but can be accessed programmatically. This is useful for storing raw results, debugging information, or data for downstream processing without cluttering the model's context.

        :::python
        <Accordion title="Example: Using artifact for raw data">
            ```python
            from langchain_core.messages import ToolMessage
            import json

            # Tool execution returns structured data
            raw_data = {"temperature": 72, "condition": "Sunny"}
            tool_message = ToolMessage(
                content="The weather is sunny with a temperature of 72°F.",
                tool_call_id="call_123",
                name="get_weather",
                artifact={"raw_data": raw_data}  # Store structured data
            )

            # Later, access the raw data programmatically
            weather_info = tool_message.artifact.get("raw_data")
            print(f"Raw weather data: {json.dumps(weather_info)}")
            ```
        </Accordion>
        :::
        :::js
        <Accordion title="Example: Using artifact for raw data">
            ```typescript
            import { ToolMessage } from "langchain";

            // Tool execution returns structured data
            const rawData = { temperature: 72, condition: "Sunny" };
            const toolMessage = new ToolMessage({
                content: "The weather is sunny with a temperature of 72°F.",
                tool_call_id: "call_123",
                name: "get_weather",
                artifact: { raw_data: rawData }  // Store structured data
            });

            // Later, access the raw data programmatically
            const weatherInfo = toolMessage.artifact.raw_data;
            console.log(`Raw weather data: ${JSON.stringify(weatherInfo)}`);
            ```
        </Accordion>
        :::
    </Note>
</Accordion>

---

## Content

You can think of a message's content as the payload of data that gets sent to the model. Messages have a `content` attribute that is loosely-typed, supporting strings and lists of untyped objects (e.g., dictionaries). This allows support for provider-native structures directly in LangChain chat models, such as [multimodal](#multimodal) content and other data.

Separately, LangChain provides dedicated content types for text, reasoning, citations, multi-modal data, server-side tool calls, and other message content. See [content blocks](#standard-content-blocks) below.

LangChain chat models accept message content in the `.content` attribute, and can contain:

1. A string
2. A list of content blocks in a provider-native format
3. A list of [LangChain's standard content blocks](#standard-content-blocks)

See below for an example using [multimodal](#multimodal) inputs:

:::python
```python
from langchain_core.messages import HumanMessage

# String content
human_message = HumanMessage("Hello, how are you?")

# Provider-native format (e.g., OpenAI)
human_message = HumanMessage(content=[
    {"type": "text", "text": "Hello, how are you?"},
    {"type": "image_url", "image_url": {"url": "https://example.com/image.jpg"}}
])

# List of standard content blocks
human_message = HumanMessage(content_blocks=[
    {"type": "text", "text": "Hello, how are you?"},
    {"type": "image", "url": "https://example.com/image.jpg"},
])
```

<Tip>

Specifying `content_blocks` when initializing a message will still populate message
`content`, but provides a type-safe interface for doing so.

</Tip>
:::

:::js
```typescript
import { HumanMessage } from "langchain";

// String content
const humanMessage = new HumanMessage("Hello, how are you?");

// Provider-native format (e.g., OpenAI)
const humanMessage = new HumanMessage({
  content: [
    { type: "text", text: "Hello, how are you?" },
    { type: "image_url", image_url: { url: "https://example.com/image.jpg" } },
  ],
});

// List of standard content blocks
const humanMessage = new HumanMessage({
  contentBlocks: [
    { type: "text", text: "Hello, how are you?" },
    { type: "image", url: "https://example.com/image.jpg" },
  ],
});
```
<Tip>

Specifying `contentBlocks` when initializing a message will still populate message
`content`, but provides a type-safe interface for doing so.

</Tip>
:::

### Standard content blocks

LangChain maintains a standard set of types for message content that works across
providers (see the [reference](#content-block-reference) section below).

:::python
Messages also implement a `content_blocks` property that will lazily parse the `content` attribute into this standard, type-safe representation. For example, messages generated from [ChatAnthropic](/oss/integrations/chat/anthropic) or [ChatOpenAI](/oss/integrations/chat/openai) will include `thinking` or `reasoning` blocks in the format of the respective provider, but these can be lazily parsed into a consistent [`ReasoningContentBlock`](#content-block-reference) representation:

<Tabs>
<Tab title="Anthropic">
```python
from langchain_core.messages import AIMessage

message = AIMessage(
    content=[
        {"type": "thinking", "thinking": "...", "signature": "WaUjzkyp..."},
        {"type": "text", "text": "..."},
    ],
    response_metadata={"model_provider": "anthropic"}
)
message.content_blocks
```
```
[{'type': 'reasoning',
  'reasoning': '...',
  'extras': {'signature': 'WaUjzkyp...'}},
 {'type': 'text', 'text': '...'}]
```
</Tab>

<Tab title="OpenAI">
```python
from langchain_core.messages import AIMessage

message = AIMessage(
    content=[
        {
            "type": "reasoning",
            "id": "rs_abc123",
            "summary": [
                {"type": "summary_text", "text": "summary 1"},
                {"type": "summary_text", "text": "summary 2"},
            ],
        },
        {"type": "text", "text": "...", "id": "msg_abc123"},
    ],
    response_metadata={"model_provider": "openai"}
)
message.content_blocks
```
```
[{'type': 'reasoning', 'id': 'rs_abc123', 'reasoning': 'summary 1'},
 {'type': 'reasoning', 'id': 'rs_abc123', 'reasoning': 'summary 2'},
 {'type': 'text', 'text': '...', 'id': 'msg_abc123'}]
```
</Tab>
</Tabs>
:::

:::js
Messages also implement a `contentBlocks` property that will lazily parse the `content` attribute into this standard, type-safe representation. For example, messages generated from [ChatAnthropic](/oss/integrations/chat/anthropic) or [ChatOpenAI](/oss/integrations/chat/openai) will include `thinking` or `reasoning` blocks in the format of the respective provider, but these can be lazily parsed into a consistent [`ReasoningContentBlock`](#content-block-reference) representation:

<Tabs>
<Tab title="Anthropic">
```typescript
import { AIMessage } from "@langchain/core/messages";

const message = new AIMessage({
    content: [
        {"type": "thinking", "thinking": "...", "signature": "WaUjzkyp..."},
        {"type": "text", "text": "...", "id": "msg_abc123"},
    ],
    response_metadata: { model_provider: "anthropic" },
});

console.log(message.contentBlocks);
```
</Tab>

<Tab title="OpenAI">
```typescript
import { AIMessage } from "@langchain/core/messages";

const message = new AIMessage({
    content: [
        {
        "type": "reasoning",
        "id": "rs_abc123",
        "summary": [
            {"type": "summary_text", "text": "summary 1"},
            {"type": "summary_text", "text": "summary 2"},
        ],
        },
        {"type": "text", "text": "..."},
    ],
    response_metadata: { model_provider: "openai" },
});

console.log(message.contentBlocks);
```
</Tab>
</Tabs>
:::

See the [integrations guides](/oss/integrations/providers) to get started with the
inference provider of your choice.

<Note>
    **Serializing standard content**

    If an application outside of LangChain needs access to the standard content block
    representation, you can opt-in to storing content blocks in message content.

    :::python
    To do this, you can set the `LC_OUTPUT_VERSION` environment variable to `v1`. Or,
    initialize any chat model with `output_version="v1"`:

    ```python
    from langchain.chat_models import init_chat_model

    model = init_chat_model("openai:gpt-5-nano", output_version="v1")
    ```
    :::
    :::js
    To do this, you can set the `LC_OUTPUT_VERSION` environment variable to `v1`. Or,
    initialize any chat model with `outputVersion: "v1"`:

    ```typescript
    import { initChatModel } from "langchain";

    const model = await initChatModel("openai:gpt-5-nano", { outputVersion: "v1" });
    ```
    :::
</Note>

### Multimodal

**Multimodality** refers to the ability to work with data that comes in different
forms, such as text, audio, images, and video. LangChain includes standard types
for these data that can be used across providers.

[Chat models](/oss/langchain/models) can accept multimodal data as input and generate
it as output. Below we show short examples of input messages featuring multimodal data:

:::python
<CodeGroup>
    ```python Image input
    # From URL
    message = {
        "role": "user",
        "content": [
            {"type": "text", "text": "Describe the content of this image."},
            {"type": "image", "url": "https://example.com/path/to/image.jpg"},
        ]
    }

    # From base64 data
    message = {
        "role": "user",
        "content": [
            {"type": "text", "text": "Describe the content of this image."},
            {
                "type": "image",
                "base64": "AAAAIGZ0eXBtcDQyAAAAAGlzb21tcDQyAAACAGlzb2...",
                "mime_type": "image/jpeg",
            },
        ]
    }

    # From provider-managed File ID
    message = {
        "role": "user",
        "content": [
            {"type": "text", "text": "Describe the content of this image."},
            {"type": "image", "file_id": "file-abc123"},
        ]
    }
    ```

    ```python PDF document input
    # From URL
    message = {
        "role": "user",
        "content": [
            {"type": "text", "text": "Describe the content of this document."},
            {"type": "file", "url": "https://example.com/path/to/document.pdf"},
        ]
    }

    # From base64 data
    message = {
        "role": "user",
        "content": [
            {"type": "text", "text": "Describe the content of this document."},
            {
                "type": "file",
                "base64": "AAAAIGZ0eXBtcDQyAAAAAGlzb21tcDQyAAACAGlzb2...",
                "mime_type": "application/pdf",
            },
        ]
    }

    # From provider-managed File ID
    message = {
        "role": "user",
        "content": [
            {"type": "text", "text": "Describe the content of this document."},
            {"type": "file", "file_id": "file-abc123"},
        ]
    }
    ```

    ```python Audio input
    # From base64 data
    message = {
        "role": "user",
        "content": [
            {"type": "text", "text": "Describe the content of this audio."},
            {
                "type": "audio",
                "base64": "AAAAIGZ0eXBtcDQyAAAAAGlzb21tcDQyAAACAGlzb2...",
                "mime_type": "audio/wav",
            },
        ]
    }

    # From provider-managed File ID
    message = {
        "role": "user",
        "content": [
            {"type": "text", "text": "Describe the content of this audio."},
            {"type": "audio", "file_id": "file-abc123"},
        ]
    }
    ```

    ```python Video input
    # From base64 data
    message = {
        "role": "user",
        "content": [
            {"type": "text", "text": "Describe the content of this video."},
            {
                "type": "video",
                "base64": "AAAAIGZ0eXBtcDQyAAAAAGlzb21tcDQyAAACAGlzb2...",
                "mime_type": "video/mp4",
            },
        ]
    }

    # From provider-managed File ID
    message = {
        "role": "user",
        "content": [
            {"type": "text", "text": "Describe the content of this video."},
            {"type": "video", "file_id": "file-abc123"},
        ]
    }
    ```
</CodeGroup>
:::

:::js
<CodeGroup>
    ```typescript Image input
    // From URL
    const message = new HumanMessage({
        content: [
            { type: "text", text: "Describe the content of this image." },
            { type: "image", url: "https://example.com/path/to/image.jpg" },
        ],
    });

    // From base64 data
    const message = new HumanMessage({
        content: [
            { type: "text", text: "Describe the content of this image." },
            {
                type: "image",
                data: "AAAAIGZ0eXBtcDQyAAAAAGlzb21tcDQyAAACAGlzb2...",
                mimeType: "image/jpeg",
            },
        ],
    });

    // From provider-managed File ID
    const message = new HumanMessage({
        content: [
            { type: "text", text: "Describe the content of this image." },
            { type: "image", fileId: "file-abc123" },
        ],
    });
    ```

    ```typescript PDF document input
    // From URL
    const message = new HumanMessage({
        content: [
            { type: "text", text: "Describe the content of this document." },
            { type: "file", url: "https://example.com/path/to/document.pdf" },
        ],
    });

    // From base64 data
    const message = new HumanMessage({
        content: [
            { type: "text", text: "Describe the content of this document." },
            {
                type: "file",
                data: "AAAAIGZ0eXBtcDQyAAAAAGlzb21tcDQyAAACAGlzb2...",
                mimeType: "application/pdf",
            },
        ],
    });

    // From provider-managed File ID
    const message = new HumanMessage({
        content: [
            { type: "text", text: "Describe the content of this document." },
            { type: "file", fileId: "file-abc123" },
        ],
    });
    ```

    ```typescript Audio input
    // From base64 data
    const message = new HumanMessage({
        content: [
            { type: "text", text: "Describe the content of this audio." },
            {
                type: "audio",
                data: "AAAAIGZ0eXBtcDQyAAAAAGlzb21tcDQyAAACAGlzb2...",
                mimeType: "audio/wav",
            },
        ],
    });

    // From provider-managed File ID
    const message = new HumanMessage({
        content: [
            { type: "text", text: "Describe the content of this audio." },
            { type: "audio", fileId: "file-abc123" },
        ],
    });
    ```

    ```typescript Video input
    // From base64 data
    const message = new HumanMessage({
        content: [
            { type: "text", text: "Describe the content of this video." },
            {
                type: "video",
                data: "AAAAIGZ0eXBtcDQyAAAAAGlzb21tcDQyAAACAGlzb2...",
                mimeType: "video/mp4",
            },
        ],
    });

    // From provider-managed File ID
    const message = new HumanMessage({
        content: [
            { type: "text", text: "Describe the content of this video." },
            { type: "video", fileId: "file-abc123" },
        ],
    });
    ```
</CodeGroup>
:::


<Warning>
    Not all models support all file types. Check the model provider's @[reference][Reference] for supported formats and size limits.
</Warning>

### Content block reference

:::python
Content blocks are represented (either when creating a message or accessing the `content_blocks` property) as a list of typed dictionaries. Each item in the list must adhere to one of the following block types:

<AccordionGroup>
    <Accordion title="Core" icon="cube">
        <AccordionGroup>
            <Accordion title="TextContentBlock" icon="text">
                **Purpose:** Standard text output

                <ParamField body="type" type="string" required>
                    Always `"text"`
                </ParamField>

                <ParamField body="text" type="string" required>
                    The text content
                </ParamField>

                <ParamField body="annotations" type="object[]">
                    List of annotations for the text
                </ParamField>

                <ParamField body="extras" type="object">
                    Additional provider-specific data
                </ParamField>

                **Example:**
                ```python
                {
                    "type": "text",
                    "text": "Hello world",
                    "annotations": []
                }
                ```
            </Accordion>
            <Accordion title="ReasoningContentBlock" icon="brain">
                **Purpose:** Model reasoning steps

                <ParamField body="type" type="string" required>
                    Always `"reasoning"`
                </ParamField>

                <ParamField body="reasoning" type="string">
                    The reasoning content
                </ParamField>

                <ParamField body="extras" type="object">
                    Additional provider-specific data
                </ParamField>

                **Example:**
                ```python
                {
                    "type": "reasoning",
                    "reasoning": "The user is asking about...",
                    "extras": {"signature": "abc123"},
                }
                ```
            </Accordion>
        </AccordionGroup>
    </Accordion>

    <Accordion title="Multimodal" icon="images">
        <AccordionGroup>
            <Accordion title="ImageContentBlock" icon="image">
                **Purpose:** Image data

                <ParamField body="type" type="string" required>
                    Always `"image"`
                </ParamField>

                <ParamField body="url" type="string">
                    URL pointing to the image location.
                </ParamField>

                <ParamField body="base64" type="string">
                    Base64-encoded image data.
                </ParamField>

                <ParamField body="id" type="string">
                    Reference ID to an externally stored image (e.g., in a provider's file system or in a bucket).
                </ParamField>

                <ParamField body="mime_type" type="string">
                    Image [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml#image) (e.g., `image/jpeg`, `image/png`)
                </ParamField>
            </Accordion>
            <Accordion title="AudioContentBlock" icon="volume-high">
                **Purpose:** Audio data

                <ParamField body="type" type="string" required>
                    Always `"audio"`
                </ParamField>

                <ParamField body="url" type="string">
                    URL pointing to the audio location.
                </ParamField>

                <ParamField body="data" type="string">
                    Base64-encoded audio data.
                </ParamField>

                <ParamField body="id" type="string">
                    Reference ID to an externally stored audio file (e.g., in a provider's file system or in a bucket).
                </ParamField>

                <ParamField body="mime_type" type="string">
                    Audio [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml#audio) (e.g., `audio/mpeg`, `audio/wav`)
                </ParamField>
            </Accordion>
            <Accordion title="VideoContentBlock" icon="video">
                **Purpose:** Video data

                <ParamField body="type" type="string" required>
                    Always `"video"`
                </ParamField>

                <ParamField body="url" type="string">
                    URL pointing to the video location.
                </ParamField>

                <ParamField body="data" type="string">
                    Base64-encoded video data.
                </ParamField>

                <ParamField body="id" type="string">
                    Reference ID to an externally stored video file (e.g., in a provider's file system or in a bucket).
                </ParamField>

                <ParamField body="mime_type" type="string">
                    Video [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml#video) (e.g., `video/mp4`, `video/webm`)
                </ParamField>
            </Accordion>
            <Accordion title="FileContentBlock" icon="file">
                **Purpose:** Generic files (PDF, etc)

                <ParamField body="type" type="string" required>
                    Always `"file"`
                </ParamField>

                <ParamField body="url" type="string">
                    URL pointing to the file location.
                </ParamField>

                <ParamField body="data" type="string">
                    Base64-encoded file data.
                </ParamField>

                <ParamField body="id" type="string">
                    Reference ID to an externally stored file (e.g., in a provider's file system or in a bucket).
                </ParamField>

                <ParamField body="mime_type" type="string">
                    File [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml) (e.g., `application/pdf`)
                </ParamField>
            </Accordion>
            <Accordion title="PlainTextContentBlock" icon="align-left">
                **Purpose:** Document text (`.txt`, `.md`)

                <ParamField body="type" type="string" required>
                    Always `"text-plain"`
                </ParamField>

                <ParamField body="text" type="string">
                    The text content
                </ParamField>

                <ParamField body="mime_type" type="string">
                    [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml) of the text (e.g., `text/plain`, `text/markdown`)
                </ParamField>
            </Accordion>
        </AccordionGroup>
    </Accordion>

    <Accordion title="Tool Calling" icon="wrench">
        <AccordionGroup>
            <Accordion title="ToolCall" icon="function">
                **Purpose:** Function calls

                <ParamField body="type" type="string" required>
                    Always `"tool_call"`
                </ParamField>

                <ParamField body="name" type="string" required>
                    Name of the tool to call
                </ParamField>

                <ParamField body="args" type="object" required>
                    Arguments to pass to the tool
                </ParamField>

                <ParamField body="id" type="string" required>
                    Unique identifier for this tool call
                </ParamField>

                **Example:**
                ```python
                {
                    "type": "tool_call",
                    "name": "search",
                    "args": {"query": "weather"},
                    "id": "call_123"
                }
                ```
            </Accordion>
            <Accordion title="ToolCallChunk" icon="puzzle-piece">
                **Purpose:** Streaming tool fragments

                <ParamField body="type" type="string" required>
                    Always `"tool_call_chunk"`
                </ParamField>

                <ParamField body="name" type="string">
                    Name of the tool being called
                </ParamField>

                <ParamField body="args" type="string">
                    Partial tool arguments (may be incomplete JSON)
                </ParamField>

                <ParamField body="id" type="string">
                    Tool call identifier
                </ParamField>

                <ParamField body="index" type="number">
                    Position of this chunk in the stream
                </ParamField>
            </Accordion>
            <Accordion title="InvalidToolCall" icon="triangle-exclamation">
                **Purpose:** Malformed calls, intended to catch JSON parsing errors.

                <ParamField body="type" type="string" required>
                    Always `"invalid_tool_call"`
                </ParamField>

                <ParamField body="name" type="string">
                    Name of the tool that failed to be called
                </ParamField>

                <ParamField body="args" type="string">
                    Raw arguments that failed to parse
                </ParamField>

                <ParamField body="error" type="string">
                    Description of what went wrong
                </ParamField>
            </Accordion>
        </AccordionGroup>
    </Accordion>

    <Accordion title="Server-Side Tool Execution" icon="server">
        <AccordionGroup>
            <Accordion title="WebSearchCall" icon="magnifying-glass">
                **Purpose:** Built-in web search

                <ParamField body="type" type="string" required>
                    Always `"web_search_call"`
                </ParamField>

                <ParamField body="query" type="string">
                    The search query to execute
                </ParamField>
            </Accordion>
            <Accordion title="WebSearchResult" icon="globe">
                **Purpose:** Search results

                <ParamField body="type" type="string" required>
                    Always `"web_search_result"`
                </ParamField>

                <ParamField body="urls" type="string[]">
                    URLs of the search results
                </ParamField>

                **Returns:** Top search results with associated URLs.
            </Accordion>
            <Accordion title="CodeInterpreterCall" icon="code">
                **Purpose:** Code execution

                <ParamField body="type" type="string" required>
                    Always `"code_interpreter_call"`
                </ParamField>

                <ParamField body="language" type="string">
                    Programming language to execute (e.g. `python`,
                    `javascript`, `sql`)
                </ParamField>

                <ParamField body="code" type="string">
                    Code to execute
                </ParamField>
            </Accordion>
            <Accordion title="CodeInterpreterResult" icon="terminal">
                **Purpose:** Execution results

                <ParamField body="type" type="string" required>
                    Always `"code_interpreter_result"`
                </ParamField>

                <ParamField body="output" type="CodeInterpreterOutput[]">
                    Output from the code execution
                </ParamField>
            </Accordion>
        </AccordionGroup>
    </Accordion>

    <Accordion title="Provider-Specific Blocks" icon="plug">
        <Accordion title="NonStandardContentBlock" icon="asterisk">
            **Purpose:** Provider-specific escape hatch

            <ParamField body="type" type="string" required>
                Always `"non_standard"`
            </ParamField>

            <ParamField body="value" type="object" required>
                Provider-specific data structure
            </ParamField>

            **Usage:** For experimental or provider-unique features
        </Accordion>

        Additional provider-specific content types may be found within the [reference documentation](/oss/integrations/providers) of each model provider.
    </Accordion>
</AccordionGroup>
:::

:::js
Content blocks are represented (either when creating a message or accessing the `contentBlocks` field) as a list of typed objects. Each item in the list must adhere to one of the following block types:

<AccordionGroup>
    <Accordion title="Core" icon="cube">
        <AccordionGroup>
            <Accordion title="ContentBlock.Text" icon="text">
                **Purpose:** Standard text output

                <ParamField body="text" type="string" required>
                    The text content
                </ParamField>

                <ParamField body="annotations" type="Citation[]">
                    List of annotations for the text
                </ParamField>

                **Example:**
                ```typescript
                {
                    type: "text",
                    text: "Hello world",
                    annotations: []
                }
                ```
            </Accordion>
            <Accordion title="ContentBlock.Reasoning" icon="brain">
                **Purpose:** Model reasoning steps

                <ParamField body="reasoning" type="string" required>
                    The reasoning content
                </ParamField>

                **Example:**
                ```typescript
                {
                    type: "reasoning",
                    reasoning: "The user is asking about..."
                }
                ```
            </Accordion>
        </AccordionGroup>
    </Accordion>

    <Accordion title="Multimodal" icon="images">
        <AccordionGroup>
            <Accordion title="ContentBlock.Multimodal.Image" icon="image">
                **Purpose:** Image data

                <ParamField body="url" type="string">
                    URL pointing to the image location.
                </ParamField>

                <ParamField body="data" type="string">
                    Base64-encoded image data.
                </ParamField>

                <ParamField body="fileId" type="string">
                    Reference ID to an externally stored image (e.g., in a provider's file system or in a bucket).
                </ParamField>

                <ParamField body="mimeType" type="string">
                    Image [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml#image) (e.g., `image/jpeg`, `image/png`)
                </ParamField>
            </Accordion>
            <Accordion title="ContentBlock.Multimodal.Audio" icon="volume-high">
                **Purpose:** Audio data

                <ParamField body="url" type="string">
                    URL pointing to the audio location.
                </ParamField>

                <ParamField body="data" type="string">
                    Base64-encoded audio data.
                </ParamField>

                <ParamField body="fileId" type="string">
                    Reference ID to an externally stored audio file (e.g., in a provider's file system or in a bucket).
                </ParamField>

                <ParamField body="mimeType" type="string">
                    Audio [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml#audio) (e.g., `audio/mpeg`, `audio/wav`)
                </ParamField>
            </Accordion>
            <Accordion title="ContentBlock.Multimodal.Video" icon="video">
                **Purpose:** Video data

                <ParamField body="url" type="string">
                    URL pointing to the video location.
                </ParamField>

                <ParamField body="data" type="string">
                    Base64-encoded video data.
                </ParamField>

                <ParamField body="fileId" type="string">
                    Reference ID to an externally stored video file (e.g., in a provider's file system or in a bucket).
                </ParamField>

                <ParamField body="mimeType" type="string">
                    Video [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml#video) (e.g., `video/mp4`, `video/webm`)
                </ParamField>
            </Accordion>
            <Accordion title="ContentBlock.Multimodal.File" icon="file">
                **Purpose:** Generic files (PDF, etc)

                <ParamField body="url" type="string">
                    URL pointing to the file location.
                </ParamField>

                <ParamField body="data" type="string">
                    Base64-encoded file data.
                </ParamField>

                <ParamField body="fileId" type="string">
                    Reference ID to an externally stored file (e.g., in a provider's file system or in a bucket).
                </ParamField>

                <ParamField body="mimeType" type="string">
                    File [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml) (e.g., `application/pdf`)
                </ParamField>
            </Accordion>
            <Accordion title="ContentBlock.Multimodal.PlainText" icon="align-left">
                **Purpose:** Document text (`.txt`, `.md`)

                <ParamField body="text" type="string" required>
                    The text content
                </ParamField>

                <ParamField body="title" type="string">
                    Title of the text content
                </ParamField>

                <ParamField body="mimeType" type="string">
                    [MIME type](https://www.iana.org/assignments/media-types/media-types.xhtml) of the text (e.g., `text/plain`, `text/markdown`)
                </ParamField>
            </Accordion>
        </AccordionGroup>
    </Accordion>

    <Accordion title="Tool Calling" icon="wrench">
        <AccordionGroup>
            <Accordion title="ContentBlock.Tools.ToolCall" icon="function">
                **Purpose:** Function calls

                <ParamField body="name" type="string" required>
                    Name of the tool to call
                </ParamField>

                <ParamField body="args" type="object" required>
                    Arguments to pass to the tool
                </ParamField>

                <ParamField body="id" type="string" required>
                    Unique identifier for this tool call
                </ParamField>

                **Example:**
                ```typescript
                {
                    type: "tool_call",
                    name: "search",
                    args: { query: "weather" },
                    id: "call_123"
                }
                ```
            </Accordion>
            <Accordion title="ContentBlock.Tools.ToolCallChunk" icon="puzzle-piece">
                **Purpose:** Streaming tool fragments

                <ParamField body="name" type="string">
                    Name of the tool being called
                </ParamField>

                <ParamField body="args" type="string">
                    Partial tool arguments (may be incomplete JSON)
                </ParamField>

                <ParamField body="id" type="string">
                    Tool call identifier
                </ParamField>

                <ParamField body="index" type="number" required>
                    Position of this chunk in the stream
                </ParamField>
            </Accordion>
            <Accordion title="ContentBlock.Tools.InvalidToolCall" icon="triangle-exclamation">
                **Purpose:** Malformed calls

                <ParamField body="name" type="string">
                    Name of the tool that failed to be called
                </ParamField>

                <ParamField body="args" type="string">
                    Raw arguments that failed to parse
                </ParamField>

                <ParamField body="error" type="string" required>
                    Description of what went wrong
                </ParamField>

                **Common errors:** Invalid JSON, missing required fields
            </Accordion>
        </AccordionGroup>
    </Accordion>

    <Accordion title="Server-Side Tool Execution" icon="server">
        <AccordionGroup>
            <Accordion title="ContentBlock.Tools.WebSearchCall" icon="magnifying-glass">
                **Purpose:** Built-in web search

                <ParamField body="query" type="string" required>
                    The search query to execute
                </ParamField>
            </Accordion>
            <Accordion title="ContentBlock.Tools.WebSearchResult" icon="globe">
                **Purpose:** Search results

                <ParamField body="urls" type="string[]" required>
                    URLs of the search results
                </ParamField>

                **Returns:** Top search results with optional snippets
            </Accordion>
            <Accordion title="ContentBlock.Tools.CodeInterpreterCall" icon="code">
                **Purpose:** Code execution

                <ParamField body="language" type="string" required>
                    Programming language to execute (e.g. `python`,
                    `javascript`, `sql`)
                </ParamField>

                <ParamField body="code" type="string" required>
                    Code to execute
                </ParamField>
            </Accordion>
            <Accordion title="ContentBlock.Tools.CodeInterpreterResult" icon="terminal">
                **Purpose:** Execution results

                <ParamField body="output" type="string" required>
                    Output from the code execution
                </ParamField>

                <ParamField body="error" type="string">
                    Error message if execution failed
                </ParamField>
            </Accordion>
        </AccordionGroup>
    </Accordion>
</AccordionGroup>

Each of these content blocks mentioned above are indvidually addressable as types when importing the `ContentBlock` type.

```typescript
import { ContentBlock } from "langchain";

// Text block
const textBlock: ContentBlock.Text = {
    type: "text",
    text: "Hello world",
}

// Image block
const imageBlock: ContentBlock.Multimodal.Image = {
    type: "image",
    url: "https://example.com/image.png",
    mimeType: "image/png",
}
```
:::

<Info>
    Content blocks were introduced as a new property on messages in LangChain v1 to standardize content formats across providers while maintaining backward compatibility with existing code. Content blocks are not a replacement for the `content` property, but rather a new property that can be used to access the content of a message in a standardized format.

    {/* :::python
    `.content_blocks` is a computed property that outputs standard blocks based on `content`. Because of this,
    content blocks will not be included in the output when a message gets stringified/serialized by default.
    :::

    :::js
    `.contentBlocks` is a computed property that outputs standard blocks based on `content`. Because of this,
    content blocks will not be included in the output when a message gets stringified/serialized by default.
    :::

    If you want to serialize a message that uses [standard content blocks](#content-block-reference) (e.g.
    if you were passing messages to a client), there's a couple of different options to instruct the model to
    output a message using standard content blocks:

    :::python
    <CodeGroup>
    ```python Model initialization
    # Default v0 (backward compatible)
    model = ChatOpenAI()

    # Explicit v1
    model = ChatOpenAI(output_version="v1")
    ```

    ```python Environment variable
    import os
    os.environ["LC_OUTPUT_VERSION"] = "v1"

    model = ChatOpenAI()  # Uses v1
    ```
    </CodeGroup>
    :::

    :::js
    <CodeGroup>
    ```typescript Model initialization
    // Default v0 (backward compatible)
    const model = new ChatOpenAI({ model: "gpt-4o" })

    // Explicit v1
    const model = new ChatOpenAI({ model: "gpt-4o", output_version: "v1" })
    ```

    ```typescript Environment variable
    process.env.LC_OUTPUT_VERSION = "v1"

    const model = new ChatOpenAI()  # Uses v1
    ```
    </CodeGroup>
    :::

    :::python
    When instructed, the model will output a message with `content` as a list of
    [standard content blocks](#content-block-reference) (the same as if you were accessing `.content_blocks`).

    ```python
    model = init_chat_model("", {
        modelProvider: "",
        outputVersion: "v1",
    })
    response = model.invoke("Analyze the sales data and show your reasoning")

    response.content  # List of ContentBlock objects
    response.content_blocks  # Same as above, but typed
    ```
    :::

    :::js
    When instructed, the model will output a message with `content` as a list of
    [standard content blocks](#content-block-reference) (the same as if you were accessing `.contentBlocks`).

    ```typescript
    const model = await initChatModel(model="", provider="", output_version="v1")
    const response = await model.invoke("Analyze the sales data and show your reasoning")

    response.content  // List of ContentBlock objects
    response.contentBlocks  // Same as above, but typed
    ```
    :::

    Models can interpret both v0 and v1 content formats, which means that you can use the same model instance
    to invoke messages that might have different content formats.

    :::python
    | Aspect | v0 | v1 (Standard) |
    |:--------|:-----------|:-------------|
    | **Default behavior** | Yes | Accessible through `.content_blocks` |
    | **Serialization** | `content` is raw model output | `content` is a list of `ContentBlock` objects |
    | **Content format** | Provider-specific | Standardized `ContentBlock` types |
    | **Type safety** | Limited | Fully typed |
    | **Multimodal support** | Basic | Comprehensive |
    :::
    :::js
    | Aspect | v0 | v1 (Standard) |
    |:--------|:-----------|:-------------|
    | **Default behavior** | Yes | Accessible through `.contentBlocks` |
    | **Serialization** | `content` is raw model output | `content` is a list of `ContentBlock` objects |
    | **Content format** | Provider-specific | Standardized `ContentBlock` types |
    | **Type safety** | Limited | Fully typed |
    | **Multimodal support** | Basic | Comprehensive |
    ::: */}
</Info>

---

## Examples

### Multi-turn conversations

Building conversational applications requires managing message history and context:

:::python
<CodeGroup>
    ```python Basic chat loop
    from langchain_core.messages import HumanMessage, AIMessage

    # Initialize conversation
    messages = [
        SystemMessage("You are a helpful assistant specializing in Python programming")
    ]

    # Simulate multi-turn conversation
    while True:
        user_input = input("You: ")
        if user_input.lower() == "quit":
            break

        # Add user message
        messages.append(HumanMessage(user_input))

        # Get model response
        response = model.invoke(messages)

        # Add assistant response to history
        messages.append(response)

        print(f"Assistant: {response.content}")
    ```

    ```python Context window management
    from langchain_core.messages import filter_messages

    def manage_conversation_window(messages, max_messages=10):
        """Keep only the system message and last N messages"""
        system_msgs = filter_messages(messages, include_types="system")
        recent_msgs = messages[-(max_messages-len(system_msgs)):]
        return system_msgs + recent_msgs

    # Usage in conversation loop
    while True:
        user_input = input("You: ")
        messages.append(HumanMessage(user_input))

        # Trim conversation to fit context window
        messages = manage_conversation_window(messages)

        response = model.invoke(messages)
        messages.append(response)
    ```
</CodeGroup>
:::

:::js
<CodeGroup>
    ```typescript Basic chat loop
    import { HumanMessage, SystemMessage } from "langchain";

    // Initialize conversation
    const messages = [
        new SystemMessage("You are a helpful assistant specializing in Python programming")
    ]

    // Simulate multi-turn conversation
    while (true) {
        const userInput = await getNextMessage();
        if (userInput.toLowerCase() === "quit") {
            break;
        }

        // Add user message
        messages.push(new HumanMessage(userInput));

        // Get model response
        const response = await model.invoke(messages);

        // Add assistant response to history
        messages.push(response);

        console.log(`Assistant: ${response.content}`);
    }
    ```

    ```typescript Context window management
    import { BaseMessage, filterMessages } from "langchain";

    function manageConversationWindow(messages: BaseMessage[], maxMessages = 10): BaseMessage[] {
        const systemMsgs = filterMessages(messages, {
            includeTypes: "system"
        });
        const recentMsgs = messages.slice(-(maxMessages - systemMsgs.length));
        return systemMsgs.concat(recentMsgs);
    }

    // Usage in conversation loop
    const messages: BaseMessage[] = [];
    while (true) {
        const userInput = await getNextMessage();
        messages.push(new HumanMessage(userInput));

        // Trim conversation to fit context window
        messages = manageConversationWindow(messages);

        const response = await model.invoke(messages);
        messages.push(response);
    }
    ```
</CodeGroup>
:::

{/* TODO: ensure these topics are covered somewhere  */}
{/*

## Message history

TODO: check functionality

### Filtering

Filter messages with sophisticated criteria for different use cases:

<AccordionGroup>
    <Accordion title="By type" icon="filter">
        Filter messages based on their role (human, AI, system or tool) and tool
        call presence.

        ```python Type-based filtering
        from langchain_core.messages import filter_messages

        messages = [
            SystemMessage("You are helpful"),
            HumanMessage("Question 1"),
            AIMessage("Answer 1"),
            HumanMessage("Question 2"),
            AIMessage("Answer 2", tool_calls=[...]),
            ToolMessage("Result", tool_call_id="123")
        ]

        # Get only human messages
        human_only = filter_messages(messages, include_types=["human"])

        # Exclude system messages
        no_system = filter_messages(messages, exclude_types=["system"])

        # Get AI messages with tool calls
        ai_with_tools = filter_messages(
            messages,
            include_types=["ai"],
            include_tool_calls=True
        )
        ```
    </Accordion>
    <Accordion title="By metadata" icon="filter">
        ```python Metadata-based filtering
        from langchain_core.messages import filter_messages

        messages = [
            HumanMessage("Hi", name="alice", metadata={"priority": "high"}),
            HumanMessage("Hello", name="bob", metadata={"priority": "low"}),
            AIMessage("Response to Alice", metadata={"model": "gpt-4"}),
            AIMessage("Response to Bob", metadata={"model": "gpt-3.5"})
        ]

        # Filter by name
        alice_messages = filter_messages(messages, include_names=["alice"])

        # Filter by custom metadata
        high_priority = filter_messages(
            messages,
            filter_func=lambda m: m.metadata.get("priority") == "high"
        )

        # Complex filtering
        gpt4_responses = filter_messages(
            messages,
            include_types=["ai"],
            filter_func=lambda m: m.metadata.get("model") == "gpt-4"
        )
        ```
    </Accordion>
    <Accordion title="By IDs" icon="filter">
        ```python ID-based filtering
        # Keep specific messages by ID
        message_ids = ["msg_001", "msg_003", "msg_005"]
        selected = filter_messages(messages, include_ids=message_ids)

        # Exclude specific messages
        excluded = filter_messages(messages, exclude_ids=["msg_002", "msg_004"])

        # Get messages after a specific ID
        def get_messages_after(messages, after_id):
            found = False
            return [
                msg for msg in messages
                if (found := found or msg.id == after_id) and msg.id != after_id
            ]
        ```
    </Accordion>
</AccordionGroup>

### Trimming strategies

Manage context window limits with intelligent trimming:

<AccordionGroup>
    <Accordion title="Token-based" icon="calculator">
        Control message history size based on token counts to fit within model context windows.

        <CodeGroup>
        ```python Basic token trimming
        from langchain_core.messages import trim_messages

        messages = [
            SystemMessage("You are a helpful assistant"),
            HumanMessage("Tell me about Python"),
            AIMessage("Python is a programming language..."),
            # ... many more messages ...
        ]

        # Keep last 1000 tokens
        trimmed = trim_messages(
            messages,
            max_tokens=1000,
            strategy="last",  # Keep most recent messages
            token_counter=model  # Use model's token counter
        )
        ```

        ```python Preserve system message highlight={6}
        # Always keep system message
        trimmed_with_system = trim_messages(
            messages,
            max_tokens=1000,
            strategy="last",
            include_system=True,  # Preserve system message
            token_counter=model
        )
        ```

        ```python Custom token counter
        # Use custom token counter
        def count_tokens(messages):
            """Custom token counting logic"""
            total = 0
            for msg in messages:
                # Approximate: 4 chars = 1 token
                total += len(msg.content) // 4
            return total

        trimmed = trim_messages(
            messages,
            max_tokens=1000,
            strategy="last",
            token_counter=count_tokens
        )
        ```
        </CodeGroup>
    </Accordion>

    <Accordion title="Message count" icon="hashtag">
        Limit conversation history by number of messages rather than tokens.

        <CodeGroup>
        ```python Keep recent messages
        # Keep last N messages
        recent_messages = trim_messages(
            messages,
            max_messages=10,
            strategy="last"
        )
        ```

        ```python Keep initial context
        # Keep first N messages after system
        initial_context = trim_messages(
            messages,
            max_messages=5,
            strategy="first",
            include_system=True
        )
        ```

        ```python Preserve tool messages
        # Custom trimming with tool message preservation
        def trim_preserve_tools(messages, max_messages=10):
            """Keep tool-related messages intact"""
            tool_messages = filter_messages(
                messages,
                include_types=["ai", "tool"],
                include_tool_calls=True
            )
            other_messages = filter_messages(
                messages,
                exclude_types=["tool"]
            )
            trimmed_other = other_messages[-max_messages:]
            return sorted(trimmed_other + tool_messages, key=lambda m: m.id)
        ```
        </CodeGroup>
    </Accordion>

    <Accordion title="Intelligent trimming strategies" icon="brain">
        Advanced strategies that preserve important context while trimming.

        <AccordionGroup>
            <Accordion title="Importance-based trimming" icon="star">
                ```python
                def smart_trim(messages, max_tokens=2000):
                    """Trim while preserving important context"""
                    # Always keep system message
                    system = filter_messages(messages, include_types=["system"])

                    # Keep messages with high importance
                    important = filter_messages(
                        messages,
                        filter_func=lambda m: m.metadata.get("important", False)
                    )

                    # Keep recent messages
                    recent = messages[-5:]

                    # Combine and deduplicate
                    combined = list({m.id: m for m in system + important + recent}.values())

                    # Trim if still over limit
                    return trim_messages(combined, max_tokens=max_tokens, strategy="last")
                ```
            </Accordion>

            <Accordion title="Sliding window approach" icon="window-restore">
                ```python
                def sliding_window_trim(messages, window_size=10, overlap=2):
                    """Keep a sliding window of messages with overlap"""
                    if len(messages) <= window_size:
                        return messages

                    # Keep system message
                    system = filter_messages(messages, include_types=["system"])

                    # Get the window
                    start_idx = max(0, len(messages) - window_size)
                    window = messages[start_idx:]

                    # Add overlap from previous context
                    if start_idx > 0:
                        overlap_msgs = messages[max(0, start_idx - overlap):start_idx]
                        window = overlap_msgs + window

                    return system + window
                ```
            </Accordion>

            <Accordion title="Topic-aware trimming" icon="tags">
                ```python
                def topic_aware_trim(messages, max_tokens=2000):
                    """Keep messages related to current topic"""
                    # Identify current topic from recent messages
                    recent = messages[-3:]
                    topics = extract_topics(recent)  # Custom topic extraction

                    # Keep topic-relevant messages
                    relevant = filter_messages(
                        messages,
                        filter_func=lambda m: any(
                            topic in m.content.lower()
                            for topic in topics
                        )
                    )

                    # Combine with system and recent
                    system = filter_messages(messages, include_types=["system"])
                    combined = system + relevant + recent

                    return trim_messages(combined, max_tokens=max_tokens)
                ```
            </Accordion>
        </AccordionGroup>
    </Accordion>
</AccordionGroup>

#### Summarization

TODO tabs?

Compress message history while preserving context:

```python Summarize conversation history
from langchain_core.prompts import ChatPromptTemplate

def summarize_messages(messages, model, max_summary_length=500):
    """Summarize a conversation history"""

    # Create summarization prompt
    prompt = ChatPromptTemplate.from_messages([
        ("system", "Summarize this conversation in {max_length} words or less. "
                   "Focus on key points and maintain context."),
        ("human", "Conversation to summarize:\n{conversation}")
    ])

    # Format conversation as text
    conversation_text = "\n".join([
        f"{msg.__class__.__name__}: {msg.text}"
        for msg in messages
    ])

    # Generate summary
    summary_msg = model.invoke(
        prompt.format_messages(
            max_length=max_summary_length,
            conversation=conversation_text
        )
    )

    return SystemMessage(
        content=f"Previous conversation summary: {summary_msg.text}",
        metadata={"type": "summary", "message_count": len(messages)}
    )
```

##### Progressive summarization

```python Rolling summarization
from langchain_core.messages import SystemMessage
from langchain_core.prompts import ChatPromptTemplate

class ConversationSummarizer:
    """Progressively summarize conversations"""

    def __init__(self, model, chunk_size=10):
        self.model = model
        self.chunk_size = chunk_size
        self.summaries = []

    def add_messages(self, messages):
        """Add messages and summarize if needed"""
        if len(messages) >= self.chunk_size:
            # Summarize the chunk
            summary = self.summarize_chunk(messages)
            self.summaries.append(summary)

            # Return summary + recent messages
            recent = messages[-3:]  # Keep last 3 messages
            return [self.get_combined_summary()] + recent
        return messages

    def summarize_chunk(self, messages):
        """Summarize a chunk of messages"""
        prompt = ChatPromptTemplate.from_messages([
            ("system", "Summarize these messages concisely:"),
            ("human", "{messages}")
        ])

        messages_text = "\n".join([f"{m.type}: {m.text}" for m in messages])
        response = self.model.invoke(
            prompt.format_messages(messages=messages_text)
        )
        return response.text

    def get_combined_summary(self):
        """Get combined summary of all chunks"""
        if not self.summaries:
            return None

        combined = " ".join(self.summaries)
        return SystemMessage(
            f"Conversation context: {combined}",
            metadata={"type": "rolling_summary"}
        )
```

*/}
